home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
ctrlc.exe
/
CTRLC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-30
|
8KB
|
234 lines
// ===========================================================
// ctrlc.c - Ctrl-C, Ctrl-Break handlers. AT-BIOS int 15h hook
// ===========================================================
//
// Modification History
// ====================
// -Sym- -Date- Who -Comments-
// ===== ====== === ==========
// none 093092 rp Modified to be standalone for upload to CI$.
// Extracted some typedefs, etc. from header file(s).
// Translated debug stuff, etc to more std syntax.
//
#include <dos.h>
// ============================================================================
// Note: All routines originally in file KBD.ASM, via TASM's ideal mode.
// File translated to straight 'C' under Turbo C++ v1.0, as part of
// eliminating all *.asm files from project. This file was then
// updated to C++ and to conform w/ Borland C++ v3.10
// ( different getvect() & setvect() typecasts, etc ). Net result,
// all files in project now compile successfully in C++ mode.
//
// !! YOU WILL GET SYNTAX ERRORS IF YOU TRY TO COMPILE IN 'C' MODE !!
// These are mainly due to the use of 'Boolean' instead of
// 'enum Boolean'. There may be others.
//
// Note: This module assumes that all keyboard input is handled
// (in another file) via BIOS int 16h functions. Thus the int 23h
// intercept should never actually be seen. It HAS NOT been tested
// with 'stdin' or 'cin' ! Note that int 23h may also called by abort
// processing (e.g. via 'Abort, Retry, Ignore').
//
// Note: This file assumes routines are being run on an AT-class machine.
// For an XT-class, the int 15h hook is NOT valid !
//
// Note: Repeated blowups have shown that variables declared inside of
// interrupt handlers should be static ! This minimizes stack usage,
// and prevents _chain_intr() from getting too confused.
// ============================================================================
////////////////////////////////////
// typedefs from header file <std.h>
////////////////////////////////////
enum Boolean { False, True };
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned long ulong;
//////////////////////////////
// Global Functions, variables
//////////////////////////////
void init_keyboard(); // module initialization (hook int's)
void term_keyboard(); // module termination (restore int's)
Boolean breakflag = False; // set to True on Ctrl-Break, Ctrl-C
Boolean sysRequest = False; // toggled on SysRq key.
// used for debug enable/disable
//////////////////
// Local variables
//////////////////
static Boolean installed = False; // Installation flag
static Boolean trap_dosbrk = True; // False will disable int 23h intercept
static Boolean trap_biosbrk = True; // False will disable int 1Bh intercept
static uchar old_dosbrk; // Saved dos break state. 'Break' will
// be disabled if trap_dosbrk == True
// and restored at program exit
static void _interrupt (_far *old15h)(...) = 0; // saved interrupt vectors
static void _interrupt (_far *old1Bh)(...) = 0;
static void _interrupt (_far *old23h)(...) = 0;
///////////////////////////////////////////////////////////////////////////////
// The BIOS Ctrl-Break trap is easiest.
// Just set the global breakflag & exit
///////////////////////////////////////////////////////////////////////////////
static void _interrupt new1Bh(...)
{
breakflag = True;
}
/////////////////////////////////////////////////
// The 80x86 family cpu's carry flag bit position
/////////////////////////////////////////////////
const unsigned CPU_CARRY = 0x0001;
///////////////////////////////////////////////////////////////////////////////
// DOS Ctrl-C is a little more difficult.
// First, set the global breakflag.
// Then clear the cpu's carry flag to tell dos to ignore the 'error' of
// a Ctrl-C character.
//
// Only argument we care about happens to be the farthest away on the stack !
///////////////////////////////////////////////////////////////////////////////
#pragma argsused
static void _interrupt _far new23h( unsigned bp, unsigned di, unsigned si,
unsigned ds, unsigned es, unsigned dx, unsigned cx, unsigned bx,
unsigned ax, unsigned ip, unsigned cs, unsigned flags, ... )
{
breakflag = True;
flags &= ~CPU_CARRY;
}
//
// trap keyboard scan codes on AT-class only
//
static Boolean trap_15h = True; // Needed if trap_sysreq or trap_scan
static Boolean trap_sysreq = True; // Trap the SysRq key
static Boolean trap_scan = False; // Trap any scan code other than sysreq
static Boolean trap_prtsc = False; // Trap PrtSc key
static Boolean trap_reboot = False; // Trap Ctrl-Alt-Del
#define BIOS_DATA 0x40 // bios data segment
const ushort SHIFT_FLAGS = 0x17; // shift key flags byte
const uchar ALT_SHIFT = 0x08; // alt shift bit flag
const uchar CTRL_SHIFT = 0x04; // ctrl shift bit flag
const uchar CTRL_ALT = ALT_SHIFT | CTRL_SHIFT;
#define FN_SYSREQ 0x85 // int 15h reg ah if sysreq hit, release
#define FN_SCAN 0x4F // int 15h reg ah on key hit, release
#define M_DEL 0x53 // delete key make
#define M_PRTSC 0x37 // prtsc key make
//
// Maybe intercept the keyboard raw-scan codes, and SysReq keys.
//
#pragma argsused
static void _interrupt _far new15h( unsigned bp, unsigned di, unsigned si,
unsigned ds, unsigned es, unsigned dx, unsigned cx, unsigned bx,
unsigned ax, unsigned ip, unsigned cs, unsigned flags, ...)
{
static uchar _far *shiftFlags =
(uchar _far *)MK_FP( BIOS_DATA, SHIFT_FLAGS );
static Boolean chain15h; // Should we chain to old handler ?
static uchar regAH; // For clarity
static uchar regAL;
chain15h = True; // Set at each entry !
regAL = (uchar) ax; // extract for clarity
regAH = (uchar)(ax >> 8);
///////////////////
// Maybe trap SysRq
///////////////////
if ( regAH == FN_SYSREQ && trap_sysreq )
{
chain15h = False;
if ( regAL )
sysRequest = (sysRequest) ? False: True;
}
////////////////////////
// Maybe trap scan codes
////////////////////////
else if ( regAH == FN_SCAN && trap_scan )
{
switch ( regAL )
{
case M_DEL:
if ( trap_reboot && (*shiftFlags & CTRL_ALT) == CTRL_ALT )
{
flags &= ~CPU_CARRY; // discard scan code
chain15h = False; // don't chain
}
break;
case M_PRTSC:
if ( trap_prtsc )
{
flags &= ~CPU_CARRY; // discard scan code
chain15h = False; // don't chain
}
break;
default:
break; // all others pass thru
}
}
if ( chain15h )
_chain_intr( old15h );
}
/////////////////////////////////
// term_keyboard() - unhook ints
/////////////////////////////////
void term_keyboard()
{
if ( !installed )
return;
if ( trap_15h )
setvect( 0x15, old15h );
if ( trap_biosbrk)
setvect( 0x1B, old1Bh );
if ( trap_dosbrk )
{
_AX = 0x3301; // set break state
_DL = old_dosbrk; // to original
geninterrupt( 0x21 );
setvect( 0x23, old23h );
}
installed = False;
}
/////////////////////////////////////////
// init_kybd() - keyboard initialization
/////////////////////////////////////////
void init_keyboard()
{
if ( installed )
return;
if ( trap_15h )
{
old15h = getvect( 0x15 );
setvect( 0x15, (void _interrupt (_far*)(...)) new15h );
}
if ( trap_biosbrk )
{
old1Bh = getvect( 0x1B );
setvect( 0x1B, new1Bh );
}
if ( trap_dosbrk )
{
_AX = 0x3302; // exchange break state
_DL = 0; // to off
geninterrupt( 0x21 );
old_dosbrk = _DL; // save original
old23h = getvect( 0x23 );
setvect( 0x23, (void _interrupt (_far*)(...)) new23h );
}
installed = True;
}